package udpGuessGame;
/** A simple datagram server.The application uses the 
 *  DatagramSocket class.
 *  The server receives one message from a client and then exits.
 *  Port: 4950.
 *  Usage: java UDPServer
 */

import java.net.*;
import java.io.*;

/**
 * 
 * @author peter Steiner & Fredrik Wallenius
 *
 */

public class UDPServer {
	
	public static final int PORT = 4444;
	public static final int MAXBUF = 2048;
	private DatagramSocket sock = null;
	private ClientData client = null;
	private byte[] buffer;
	private DatagramPacket packet;
	private GuessGame guessMyNumber;
	private final int WAITING = 0;
	private final int WAITFIRSTNUMBER = 1;
	private final int PLAYING = 2;

	/**
	 * Guess game udp server
	 */
	public UDPServer(){
		int state=0;
		
		try {
			sock = new DatagramSocket(PORT);
			client = new ClientData();
			System.out.println("Server waiting for message...");
			
			while(true){
			
				String message = recieveMessage();
			
				if(state == WAITING){
					if(message.equalsIgnoreCase("START")){
						System.out.println("Server recieved new player");
						//Set current players connection data.
						client.setClientAddr(packet.getAddress());
						client.setPort(packet.getPort());
						
						//ACK with "OK"
						sendMessage("OK", client.getClientAddr(), client.getPort());
						
						//Start game
						guessMyNumber = new GuessGame();
						
						state = WAITFIRSTNUMBER;
						message = null;
					}
				}
				if(state == WAITFIRSTNUMBER){	
					if(message != null){
						try{
							int nr = Integer.parseInt(message);
							System.out.println( nr );
							message = guessMyNumber.guessNr(nr);
							sendMessage(message, client.getClientAddr(), client.getPort());	
							state = PLAYING;
							message = null;
						}catch(Exception e){
							state = WAITING;
							System.out.println("[Server]: invalid message " + message + " returning to state WAITING");
							sendMessage("INVALID", client.getClientAddr(), client.getPort());	
						}
					}
				}
				if(state == PLAYING){
					if(message != null){
						try{
							int nr = Integer.parseInt(message);
							System.out.println("[Server]: client guessed " + nr );
							message = guessMyNumber.guessNr(nr);
							sendMessage(message, client.getClientAddr(), client.getPort());
							
							//Test guessGame answer
							if(message.equalsIgnoreCase("CORRECT")){
								state = WAITING;
								client = new ClientData();
							}
						
						}catch(Exception e){
							System.out.println("[Server]: invalid message " + message + " state PLAYING");
							sendMessage("INVALID", client.getClientAddr(), client.getPort());	
						}
					}
				}
			}
			
		} catch (SocketException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		finally {
			sock.close();
			System.out.println("[Server]: UDPServer done.");
		}
	}
	
	/**
	 * Recieve message, check sender
	 * @return String / if sender is current client
	 * @return null String / else
	 * @throws IOException
	 */
	private String recieveMessage() throws IOException{
		String message;
		buffer = new byte[MAXBUF];
		packet = new DatagramPacket(buffer, buffer.length);
		sock.receive(packet);
		if(checkSender(packet)){
			message = new String(packet.getData()).trim();
			//System.out.println("[Server]: " + message);
			return  message;
		}else
			return null;
	}
	
	/**
	 * Check if packet sender is current client
	 * @param packet
	 * @return bool
	 * @throws IOException
	 */
	private boolean checkSender(DatagramPacket packet) throws IOException{
		//If srever has no client
		if(client.getClientAddr() == null)
			return true;
		//If datagram SENDER is current CLIENT!?
		if( ( packet.getAddress().getHostAddress().equalsIgnoreCase(client.getClientAddr().getHostAddress()) && packet.getPort() == client.getPort()) )
			return true;
		//Respond BUSY to SENDER wich is not current CLIENT
		sendMessage("BUSY", packet.getAddress(), packet.getPort());
		return false;
	}
	
	/**
	 * Send message as datagram to given adress and port
	 * @param message
	 * @param inetAddr
	 * @param port
	 * @throws IOException
	 */
	private void sendMessage(String message, InetAddress inetAddr, int port) throws IOException{
		System.out.println("[Server]: response "  + message);
		buffer = new byte[MAXBUF];
		buffer = message.getBytes();
		packet = new DatagramPacket(buffer, buffer.length, inetAddr, port);
		sock.send(packet);
	}
}